home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / stevi69s.zip / DOS.C < prev    next >
Text File  |  1990-04-24  |  25KB  |  1,108 lines

  1. /* $Header:
  2.  *
  3.  * MSDOS support for Stevie.
  4.  * Many of the functions in this file have two versions:
  5.  *   -    The original version, using ANSI escape sequences
  6.  *    (by Tim Thompson and/or Tony Andrews).
  7.  *    It requires a non-IBM ANSI driver, such as the shareware NANSI.SYS.
  8.  *   -    The BIOS-function version (by Larry A. Shurr).  The BIOS version
  9.  *    doesn't require an enhanced console driver such as NANSI.SYS.
  10.  *    Invoke it by #defining BIOS in ENV.H.
  11.  * Dave Tutelman has incorporated many features of Larry Shurr's BIOS
  12.  * version (such as colors and 43-line mode) into the ANSI version.
  13.  * v1.1 Using the "__TURBOC__" define Turbo C itself has,
  14.  *        rather than the bogus "TURBOC" define.
  15.  */
  16.  
  17. #include "stevie.h"
  18. #include <stdio.h>
  19. #include <dos.h>
  20. #include <signal.h>
  21.  
  22. char    *getenv();
  23.  
  24. static    char    getswitch();
  25. static    void    setswitch();
  26.  
  27. #ifdef BIOS
  28. void bios_t_ed();
  29. void bios_t_el();
  30. #endif
  31.  
  32. enum hostval_e {hIBMPC, hTIPRO};
  33. typedef enum hostval_e hostval;
  34. static    hostval    host_type   = 0;    /* Gets host computer type */
  35.  
  36. static    char    bgn_color   = 0x7;    /* For saving orig color */
  37. static    char    quitting_now= 0;    /* Set for windexit() */
  38. static    int    crt_int     = 0;        /* Gets CRT BIOS interrupt */
  39. static    char    bgn_page    = 0;    /* For saving current page (IBM PC) */
  40. static    char    bgn_mode    = 0;    /* For saving video mode (IBM PC) */
  41.  
  42. #ifdef BIOS
  43. static    int    sav_curattr = 0;    /* For saving cursor attributes */
  44. static    int    sav_curpos  = 0;    /* For saving cursor position */
  45. #endif
  46.  
  47. #ifdef __TURBOC__        /* v1.1 local prototypes */
  48. void vbeep(void);
  49. void setcolor (int color);
  50. void set_mode (int m);
  51. #ifdef BIOS
  52. int set_25 (int lines);    /* set display to 25 line mode */
  53. int set_43 (int lines);    /* set display to 43 line mode */
  54. #else
  55. void setraw (int r);
  56. void set_25 (void);
  57. void set_43 (void);
  58. void send_setmode (int m);
  59. #endif
  60. #endif
  61.  
  62. /*
  63.  * inchar() - get a character from the keyboard
  64.  */
  65. int
  66. inchar()
  67. {
  68.     int    c;
  69.  
  70.     got_int = FALSE;
  71.  
  72.     for (;;beep()) {    /* loop until we get a valid character */
  73.  
  74.         flushbuf();    /* flush any pending output */
  75.  
  76.         switch (c = getch()) {
  77.         case 0x1e:
  78.             return K_CCIRCM;
  79.         case 0:                /* special key */
  80.             if (State != NORMAL) {
  81.                 c = getch();    /* throw away next char */
  82.                 continue;    /* and loop for another char */
  83.             }
  84.             switch (c = getch()) {
  85.             case 0x50:
  86.                 return K_DARROW;
  87.             case 0x48:
  88.                 return K_UARROW;
  89.             case 0x4b:
  90.                 return K_LARROW;
  91.             case 0x4d:
  92.                 return K_RARROW;
  93.             case 0x47:        /* Home key */
  94.                 stuffin("1G");
  95.                 return -1;
  96.             case 0x4f:        /* End key */
  97.                 stuffin("G");
  98.                 return -1;
  99.             case 0x51:        /* PgDn key */
  100.                 stuffin(mkstr(CTRL('F')));
  101.                 return -1;
  102.             case 0x49:        /* PgUp key */
  103.                 stuffin(mkstr(CTRL('B')));
  104.                 return -1;
  105.             case 0x52:        /* insert key */
  106.                 return K_INSERT;
  107.             case 0x53:        /* delete key */
  108.                 stuffin("x");
  109.                 return -1;
  110.             /*
  111.              * Hard-code some useful function key macros.
  112.              */
  113.             case 0x3b: /* F1 */
  114.                 stuffin(":help\n");
  115.                 return -1;
  116.             case 0x3c: /* F2 */
  117.                 stuffin(":n\n");
  118.                 return -1;
  119.             case 0x55: /* SF2 */
  120.                 stuffin(":n!\n");
  121.                 return -1;
  122.             case 0x3d: /* F3 */
  123.                 stuffin(":N\n");
  124.                 return -1;
  125.             case 0x56: /* SF3 */
  126.                 stuffin(":N!\n");
  127.                 return -1;
  128.             case 0x3e: /* F4 */
  129.                 stuffin(":e #\n");
  130.                 return -1;
  131.             case 0x57: /* SF4 */
  132.                 stuffin(":e! #\n");
  133.                 return -1;
  134.             case 0x3f: /* F5 */
  135.                 stuffin(":rew\n");
  136.                 return -1;
  137.             case 0x58: /* SF5 */
  138.                 stuffin(":rew!\n");
  139.                 return -1;
  140.             case 0x40: /* F6 */
  141.                 stuffin("]]");
  142.                 return -1;
  143.             case 0x59: /* SF6 */
  144.                 stuffin("[[");
  145.                 return -1;
  146.             case 0x42: /* F8 - Set up global substitute */
  147.                 stuffin(":1,$s/");
  148.                 return -1;
  149.             case 0x43: /* F9 - declare C variable */
  150.                 stuffin("yyp!!cdecl\n");
  151.                 return -1;
  152.             case 0x5C: /* SF9 - explain C declaration */
  153.                 stuffin("yyp^iexplain \033!!cdecl\n");
  154.                 return -1;
  155.             case 0x44: /* F10 - save & quit */
  156.                 stuffin(":x\n");
  157.                 return -1;
  158.             case 0x5D: /* F10 - quit without saving */
  159.                 stuffin(":q!\n");
  160.                 return -1;
  161.             default:
  162.                 break;
  163.             }
  164.             break;
  165.  
  166.         default:
  167.             return c;
  168.         }
  169.     }
  170. }
  171.  
  172.  
  173. static    int    bpos = 0;
  174. #ifdef BIOS
  175.  
  176. #define    BSIZE    256
  177. static    char    outbuf[BSIZE];
  178.  
  179. /* Flushbuf() is used a little differently here in the BIOS-only interface
  180.  * than in the case of other systems.  In general, the other systems buffer
  181.  * large amounts of text and screen management data (escape sequences).
  182.  * Here, only text is buffered, screen management is performed using BIOS
  183.  * calls.  Hence, the buffer is much smaller since no more than one line of
  184.  * text is buffered.  Also, screen management calls must assure that the
  185.  * buffered text is output before performing the requested function.
  186.  *
  187.  * O.K.  Now I had better explain the tricky code sequences for IBM PC and
  188.  * TI Pro.  In both cases, the tricks involve: 1) getting the text written
  189.  * to the display as quickly as possible in the desired color and 2) assur-
  190.  * ing that the cursor is positioned immediately following the latest text
  191.  * output.
  192.  *
  193.  * On the IBM PC, we output the first character using the "write character
  194.  * with attribute" function followed by code which outputs the buffer, a
  195.  * character at a time, using the "write tty" function.  The first write
  196.  * sets the display attributes, which are then reused by the "write tty"
  197.  * function.  The "write tty" is then used to quickly write the data while
  198.  * advancing the cursor.  The "write character with attribute" function
  199.  * does not advance the cursor and so cannot be used to write the entire
  200.  * buffer without additional code to advance the cursor in a separate oper-
  201.  * ation.  Even though the first character in each buffer gets written
  202.  * twice, the result is still substantially faster than it would be using a
  203.  * "write character with attribute" - "[re]position cursor" sequence.
  204.  *
  205.  * On the TI Pro, we output the entire buffer using the "write character
  206.  * string with attribute" function which is fast and convenient.  Unfortun-
  207.  * ately, it does not advance the cursor.  Therefore, we include code which
  208.  * determines the current location of the cursor, writes the buffer, then
  209.  * positions the cursor at the end of the new data.
  210.  *
  211.  * I admit it, this is tricky, but it makes display updates much faster
  212.  * than the would be using a more straightforward approach.
  213.  */
  214.  
  215.  
  216. void
  217. flushbuf()                /* Flush buffered output to display */
  218. {
  219.     union    REGS    inregs, curregs, outregs;
  220.  
  221.     if (bpos != 0) {
  222.         char    *bptr = outbuf;
  223.  
  224.         switch (host_type) {
  225.         case hIBMPC:
  226.             inregs.h.ah = 0x09;
  227.             inregs.h.al = *bptr;
  228.             inregs.h.bh = bgn_page;
  229.             inregs.h.bl = P(P_CO);
  230.             inregs.x.cx = 1;
  231.             int86(crt_int, &inregs, &outregs);
  232.             inregs.h.ah = 0x0E;
  233.             while (bpos-- > 0) {
  234.                 inregs.h.al = *bptr++;
  235.                 int86(crt_int, &inregs, &outregs);
  236.             }
  237.             break;
  238.         case hTIPRO:
  239.             curregs.h.ah = 0x03;
  240.             int86(crt_int, &curregs, &curregs);
  241.             inregs.h.ah = 0x10;
  242.             inregs.h.al = P(P_CO);
  243.             inregs.x.bx = FP_OFF(outbuf);
  244.             inregs.x.cx = bpos;
  245.             inregs.x.dx = FP_SEG(outbuf);
  246.             int86(crt_int, &inregs, &outregs);
  247.             curregs.h.ah = 0x02;
  248.             curregs.h.dh += bpos;
  249.             int86(crt_int, &curregs, &outregs);
  250.             break;
  251.         }
  252.     }
  253.     bpos = 0;
  254. }
  255.  
  256. void
  257. write_tty(c)                /* Used to execute control chars */
  258. char    c;
  259. {
  260.     int    curcol;
  261.  
  262.     union    REGS    inregs, curregs, outregs;
  263.  
  264.     flushbuf(); \
  265.  
  266.     switch (c) {
  267.     case '\t':
  268.         inregs.h.ah = 0x09;
  269.         inregs.h.al = ' ';
  270.         inregs.h.bh = bgn_page;
  271.         inregs.h.bl = P(P_CO);
  272.         inregs.x.cx = 1;
  273.         int86(crt_int, &inregs, &outregs);
  274.         inregs.h.ah = 0x0E;
  275.         int86(crt_int, &inregs, &outregs);
  276.         curregs.h.ah = 0x03;
  277.         curregs.h.bh = bgn_page;
  278.         int86(crt_int, &curregs, &outregs);
  279.         curcol = host_type == hIBMPC ? outregs.h.dl : outregs.h.dh;
  280.         while (curcol++ % P(P_TS)) int86(crt_int, &inregs, &outregs);
  281.         break;
  282.     case '\n':
  283.         if (host_type == hTIPRO) bios_t_el();
  284.         /* No break, fall through to default action. */
  285.     default:
  286.         inregs.h.ah = 0x0E;
  287.         inregs.h.bh = bgn_page;
  288.         inregs.h.al = c;
  289.         int86(crt_int, &inregs, &outregs);
  290.         break;
  291.     }
  292. }
  293.  
  294. #else        /* Not BIOS */
  295.  
  296. #define    BSIZE    2048
  297. static    char    outbuf[BSIZE];
  298.  
  299. void
  300. flushbuf()
  301. {
  302.     if (bpos != 0)
  303.         write(1, outbuf, bpos);
  304.     bpos = 0;
  305. }
  306.  
  307. #endif
  308.  
  309.  
  310. /*
  311.  * Macro to output a character. Used within this file for speed.
  312.  *
  313.  * This macro had to be upgraded for the BIOS-only version because we
  314.  * cannot count on flushbuf() to execute control characters such as
  315.  * end-of-line or tab.  Therefore, when we encounter one, we flush
  316.  * the buffer and call a routine which executes the character.
  317.  */
  318.  
  319. #ifdef BIOS
  320.  
  321. #define    outone(cc) {                 \
  322.   register char ch = cc;             \
  323.   if (ch >= ' ') {                   \
  324.     outbuf[bpos++] = ch;             \
  325.     if (bpos >= BSIZE) flushbuf();   \
  326.   } else write_tty(ch);              \
  327. }
  328.  
  329. #else
  330.  
  331. #define    outone(c)    outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
  332.  
  333. #endif
  334.  
  335. /*
  336.  * Function version for use outside this file.
  337.  */
  338.  
  339. void
  340. outchar(c)
  341. char    c;
  342. {
  343.     outone(c);
  344. }
  345.  
  346. /*
  347.  * outstr(s) - write a string to the console
  348.  */
  349.  
  350. void
  351. outstr(s)
  352. char    *s;
  353. {
  354.     while (*s) {
  355.         outone(*s++);
  356.     }
  357. }
  358.  
  359. void
  360. beep()
  361. {
  362.     if ( P(P_VB) )
  363.         vbeep();
  364.     else
  365.         outchar('\007');
  366. }
  367.  
  368. void vbeep()        /* "Visual Bell" - reverse color flash */
  369. {
  370.     unsigned char oldcolor, revcolor, temp;
  371.  
  372.     oldcolor = P(P_CO);
  373.  
  374.     /* put reverse color in revcolor */
  375.     revcolor = (P(P_CO) & 0x07) << 4;    /* foregnd -> bkgnd */
  376.     temp     = (P(P_CO) & 0x70) >> 4;    /* bkgnd -> foregnd */
  377.     revcolor  |= temp;
  378.  
  379.     /* Flash revcolor, then back */
  380.     setcolor (revcolor);
  381.     flushbuf();
  382. #ifdef __TURBOC__        /* v1.1 */
  383.     delay (100);
  384. #endif
  385.     setcolor (oldcolor);
  386.     windgoto (Cursrow, Curscol);
  387.     flushbuf();
  388. }
  389.  
  390.  
  391. #ifndef __TURBOC__        /* v1.1 */
  392. sleep(n)
  393. int    n;
  394. {
  395.     /*
  396.      * Should do something reasonable here.
  397.      */
  398. }
  399. #endif
  400.  
  401. void
  402. pause()
  403. {
  404. /*    long    l; v1.1 unused */
  405.  
  406.     flushbuf();
  407.  
  408. #ifdef __TURBOC__        /* v1.1 */
  409.     delay (600);    /* "stop" for a fraction of a second */
  410. #else
  411.     /*
  412.      * Should do something better here...
  413.      */
  414.     for (l=0; l < 5000 ;l++)
  415.         ;
  416. #endif
  417. }
  418.  
  419. void
  420. sig()
  421. {
  422.     signal(SIGINT, sig);
  423.  
  424.     got_int = TRUE;
  425. }
  426.  
  427. static    char    schar;        /* save original switch character */
  428.  
  429. /*    While Larry Shurr's addition of color and mode support was
  430.  *    dependent on #define BIOS, there's no reason it needs to be.
  431.  *    The BIOS is always there, even if NANSI.SYS isn't.  We'll
  432.  *    use the BIOS where appropriate, and extend support to
  433.  *    all cases of #define DOS.  This is especially true of the
  434.  *    setup in windinit() and the termination in windexit().
  435.  */
  436.  
  437. void
  438. windinit()
  439. {
  440.     union    REGS    regs;
  441. /*    struct    SREGS    sregs; never used */
  442.  
  443.     /* The "SYSROM..." string is a signature in the TI Pro's ROM which
  444.      * which we can look for to determine whether or not we're running
  445.      * on a TI Pro.  If we don't find it at F400:800D,
  446.      * we assume we're running on an IBM PC or clone.
  447.      * Unfortunately, the signature is actually
  448.      * the system ROM's copyright notice though you will note that the
  449.      * year is omitted.  Still, placing it in this program might
  450.      * inadvertantly make it appear to be an official copyright notice
  451.      * for THIS program.  Hence, I have surrounded the signature
  452.      * string with disclaimers.
  453.      */
  454.  
  455.         static    char far *disclaimer1 =
  456.       "The following is *NOT* a copyright notice for this program: ";
  457.  
  458.     static    char far *ti_sig =
  459.           "SYSROM (c) Copyright Texas Instruments Inc.";
  460.  
  461.     static    char far *disclaimer2[] = {
  462.       "\nInstead, it is a signature string we look for ",
  463.       "to distinguish the TI Pro computer.\n",
  464.       "Actually, this program is in the public domain."
  465.     };
  466.  
  467.     static char far    *ti_sig_addr = (char far *)0xF400800D;
  468.     static int ti_sig_len = sizeof(ti_sig) - 1;
  469.  
  470.     /* Identify the host type.  Look for signature in TI Pro ROM.  If */
  471.     /* found, set host type to TI Pro, else assume host is an IBM PC. */
  472.  
  473.     host_type = strncmp(ti_sig, ti_sig_addr, ti_sig_len) ? hIBMPC : hTIPRO;
  474.  
  475.     /* Next, perform host-dependent initialization. */
  476.  
  477.     switch (host_type) {
  478.     case hIBMPC:
  479.         /* Get the video mode info */
  480.         crt_int = 0x10;
  481.         regs.h.ah = 0x0F;
  482.         int86(crt_int, ®s, ®s);
  483.         bgn_page = regs.h.bh;
  484.         bgn_mode = regs.h.al;
  485.         Columns = regs.h.ah;
  486.         /*  Find the starting color, and save to restore later */
  487.         regs.h.ah = 8;        /* Read char/attr BIOS fn */
  488.         regs.h.bh = bgn_page;
  489.         int86(crt_int, ®s, ®s);
  490.         bgn_color = (int) regs.h.ah;
  491.         P(P_CO) = bgn_color;
  492.         break;
  493.     case hTIPRO:
  494.         Columns = 80;
  495.         crt_int = 0x49;
  496.         P(P_CO) = 0x0F;
  497.         break;
  498.  
  499.     default:
  500.         Columns = 80;
  501.         break;
  502.     }
  503.  
  504.     P(P_LI) = Rows = 25;
  505.  
  506.     schar = getswitch();
  507.     setswitch('/');
  508.  
  509.     signal(SIGINT, sig);
  510. #ifndef BIOS
  511.     setraw (1);
  512. #endif
  513. }
  514.  
  515. void
  516. windexit(r)
  517. int r;
  518. {
  519.  
  520.     union    REGS    regs;
  521.  
  522.     quitting_now = 1;
  523.  
  524.     /* Restore original color */
  525.     setcolor (bgn_color);
  526.  
  527.     if (host_type == hIBMPC) {
  528.         /* If we've changed any of the setup, reset the mode.
  529.          * Otherwise, leave stuff on the screen.
  530.          */
  531.         regs.h.ah = 0x0F;    /* "Get-mode" BIOS fn */
  532.         int86(0x10, ®s, ®s);
  533.         if (bgn_mode != regs.h.al)
  534.             set_mode (bgn_mode);
  535.     }
  536.  
  537.     flushbuf();
  538.     setswitch(schar);
  539. #ifndef BIOS
  540.     setraw(0);
  541. #endif
  542.     exit(r);
  543. }
  544.  
  545.  
  546. #ifndef BIOS
  547. /*    Setraw sets the console driver into raw mode, which makes it run
  548.  *    somewhat faster.  Details of the function:
  549.  *    If r=1, remember current mode, and set into raw mode.
  550.  *       r=0, return to the original mode.
  551.  */
  552.  
  553. void setraw (r)
  554.   int    r;
  555. {
  556.     static int origr=0;    /* save the original r */
  557.     union REGS rr;
  558.  
  559.     /* Do IOCTL call to get current control info */
  560.     rr.x.ax = 0x4400;    /* Read IOCTL info - DOS fn */
  561.     rr.x.bx = 1;        /* Handle for stdout */
  562.     intdos (&rr, &rr);
  563.  
  564.     /* Save relevant info, and modify for "set" call */
  565.     if (r) {
  566.         origr = rr.h.dl & 0x20;        /* save current "raw" bit */
  567.         rr.h.dl = rr.h.dl | 0x20;    /* set "raw" bit */
  568.     }
  569.     else
  570.         rr.h.dl = (rr.h.dl & (~0x20)) | (origr & 0x20);
  571.  
  572.     /* Do IOCTL call to set control info */
  573.     rr.x.ax = 0x4401;    /* Set IOCTL function call */
  574.     rr.x.bx = 1;        /* Handle for stdout */
  575.     rr.h.dh = 0;        /* DL already set up */
  576.     intdos (&rr, &rr);
  577. }
  578. #endif
  579.  
  580.  
  581. void
  582. windgoto(r, c)                /* Move cursor to r'ow & c'olumn */
  583. register int    r, c;
  584. {
  585. #ifdef BIOS
  586.     union    REGS    inregs, outregs;
  587.  
  588.     if (bpos > 0) flushbuf();
  589.  
  590.     inregs.h.ah = 0x02;
  591.  
  592.     switch (host_type) {
  593.     case hIBMPC :
  594.         inregs.h.bh = bgn_page;
  595.         inregs.h.dh = r;
  596.         inregs.h.dl = c;
  597.         break;
  598.     case hTIPRO:
  599.         inregs.h.dh = c;
  600.         inregs.h.dl = r;
  601.         break;
  602.     }
  603.  
  604.     int86(crt_int, &inregs, &outregs);
  605.  
  606. #else        /* Not BIOS */
  607.  
  608.     r += 1;
  609.     c += 1;
  610.  
  611.     /*
  612.      * Check for overflow once, to save time.
  613.      */
  614.     if (bpos + 8 >= BSIZE)
  615.         flushbuf();
  616.  
  617.     outbuf[bpos++] = '\033';
  618.     outbuf[bpos++] = '[';
  619.     if (r >= 10)
  620.         outbuf[bpos++] = r/10 + '0';
  621.     outbuf[bpos++] = r%10 + '0';
  622.     outbuf[bpos++] = ';';
  623.     if (c >= 10)
  624.         outbuf[bpos++] = c/10 + '0';
  625.     outbuf[bpos++] = c%10 + '0';
  626.     outbuf[bpos++] = 'H';
  627.  
  628. #endif
  629. }
  630.  
  631. FILE *
  632. fopenb(fname, mode)
  633. char    *fname;
  634. char    *mode;
  635. {
  636.     FILE    *fopen();
  637.     char    modestr[16];
  638.  
  639.     sprintf(modestr, "%sb", mode);
  640.     return fopen(fname, modestr);
  641. }
  642.  
  643. static    char
  644. getswitch()
  645. {
  646.     union    REGS    inregs, outregs;
  647.  
  648.     inregs.h.ah = 0x37;
  649.     inregs.h.al = 0;
  650.  
  651.     intdos(&inregs, &outregs);
  652.  
  653.     return outregs.h.dl;
  654. }
  655.  
  656. static    void
  657. setswitch(c)
  658. char    c;
  659. {
  660.     union    REGS    inregs, outregs;
  661.  
  662.     inregs.h.ah = 0x37;
  663.     inregs.h.al = 1;
  664.     inregs.h.dl = c;
  665.  
  666.     intdos(&inregs, &outregs);
  667. }
  668.  
  669. #define    PSIZE    128
  670.  
  671. /*
  672.  * fixname(s) - fix up a dos name
  673.  *
  674.  * Takes a name like:
  675.  *
  676.  *    \x\y\z\base.ext
  677.  *
  678.  * and trims 'base' to 8 characters, and 'ext' to 3.
  679.  */
  680. char *
  681. fixname(s)
  682. char    *s;
  683. {
  684.     char    *strchr(), *strrchr();
  685.     static    char    f[PSIZE];
  686.     char    base[32];
  687.     char    ext[32];
  688.     char    *p;
  689.     int    i;
  690.  
  691.     strcpy(f, s);
  692.  
  693.     for (i=0; i < PSIZE ;i++)
  694.         if (f[i] == '/')
  695.             f[i] = '\\';
  696.  
  697.     /*
  698.      * Split the name into directory, base, extension.
  699.      */
  700.     if ((p = strrchr(f, '\\')) != NULL) {
  701.         strcpy(base, p+1);
  702.         p[1] = '\0';
  703.     } else {
  704.         strcpy(base, f);
  705.         f[0] = '\0';
  706.     }
  707.  
  708.     if ((p = strchr(base, '.')) != NULL) {
  709.         strcpy(ext, p+1);
  710.         *p = '\0';
  711.     } else
  712.         ext[0] = '\0';
  713.  
  714.     /*
  715.      * Trim the base name if necessary.
  716.      */
  717.     if (strlen(base) > 8)
  718.         base[8] = '\0';
  719.  
  720.     if (strlen(ext) > 3)
  721.         ext[3] = '\0';
  722.  
  723.     /*
  724.      * Paste it all back together
  725.      */
  726.     strcat(f, base);
  727.     strcat(f, ".");
  728.     strcat(f, ext);
  729.  
  730.     return f;
  731. }
  732.  
  733. void
  734. doshell(cmd)
  735. char    *cmd;
  736. {
  737.     if (cmd == NULL)
  738.         if ((cmd = getenv ("COMSPEC")) == NULL)
  739.             cmd = "command.com";
  740.  
  741.     system(cmd);
  742.     wait_return();
  743. }
  744.  
  745.  
  746. /*
  747.  *    setcolor (color)
  748.  *    Set the screen attributes (basically, color) to value co.
  749.  *    The color attributes for a DOS machine are the BIOS colors
  750.  *    for text.  Where BIOS is not defined, we map the Escape
  751.  *    sequences to the NANSI.SYS equivalents of the BIOS colors.
  752.  */
  753.  
  754. void setcolor (color)
  755.   int    color;
  756. {
  757. #ifdef BIOS
  758.     P(P_CO) = host_type == hIBMPC ? color : ((color & 0x17) | 0x08);
  759. #else
  760.     unsigned char work;
  761.  
  762.     /* Send the ANSI define-attribute sequence */
  763.     outone('\033');
  764.     outone('[');
  765.     outone('0');        /* Normal color */
  766.     outone(';');
  767.     /* BIOS-to-NANSI color conversion may look a little bizarre.
  768.      * They have different bit orderings to represent the
  769.      * color (BIOS=RGB, NANSI=BGR).
  770.      *
  771.      * First put the foreground color.
  772.      */
  773.     work = 0;
  774.     if (color & 1)        work += 4;    /* Blue */
  775.     if (color & 2)        work += 2;    /* Green */
  776.     if (color & 4)        work += 1;    /* Red */
  777.     outone('3');        /* NANSI foreground starts at 30 */
  778.     outone(work + '0');
  779.     outone(';');
  780.     /*  Now the background color */
  781.     work = 0;
  782.     if (color & 0x10)    work += 4;    /* Blue */
  783.     if (color & 0x20)    work += 2;    /* Green */
  784.     if (color & 0x40)    work += 1;    /* Red */
  785.     outone('4');        /* NANSI background starts at 40 */
  786.     outone(work + '0');
  787.     /*  Do the intensity and blinking, if any  */
  788.     if (color & 8) {    /* intensity */
  789.         outone(';');
  790.         outone('1');
  791.     }
  792.     if (color & 0x80) {    /* blink */
  793.         outone(';');
  794.         outone('5');
  795.     }
  796.     /*  The 'm' suffix means "set graphic rendition"  */
  797.     outone('m');
  798.     P(P_CO) = color;
  799.  
  800. #endif        /* Not BIOS */
  801.  
  802.     if (!quitting_now) {
  803.         screenclear();
  804.         updatescreen();
  805.     }
  806. }
  807.  
  808.  
  809. /*    setrows (r)
  810.  *    Sets the screen to "r" rows, or lines, where "r" is a feasible
  811.  *    value for the IBM PC with some common display.  In this function:
  812.  *   -    We set the mode to 25-line or 43-line mode, assuming the display
  813.  *    supports the requested mode.
  814.  *   -    We set the logical number of lines that Stevie uses to "r",
  815.  *    so that the screen USED may not be the same as the physical screen.
  816.  *
  817.  *    The function returns the number of rows set.
  818.  */
  819. setrows (r)
  820.   int r;
  821. {
  822.     int    rphys, rlog;    /* physical and logical "r" */
  823.  
  824.     rphys = (r <= 25) ? 25 : 43 ;
  825.     rlog  = (r <= 50) ? r : 50;
  826.  
  827.     /* Set the mode to correspond to the number of lines */
  828.     set_mode (rphys);
  829.  
  830.     return (rlog);
  831. }
  832.  
  833. void set_mode (m)
  834.   int m;
  835. {
  836. #ifndef BIOS            /* v1.1 */
  837.     set_25 ();
  838.     if (m == 43)
  839.         set_43 ();
  840. #else
  841.     set_25(m);
  842.     if (m == 43)
  843.         set_43(m);
  844. #endif
  845. }
  846.  
  847. #ifdef BIOS
  848.  
  849. int
  850. set_25(lines)            /* Set display to 25 line mode */
  851. int    lines;
  852. {
  853.     union    REGS    inregs, outregs;
  854.  
  855.     switch (host_type) {
  856.     case hIBMPC:
  857.         inregs.h.ah = 0x00;
  858.         inregs.h.al = bgn_mode;
  859.         int86(crt_int, &inregs, &outregs);
  860.         break;
  861.     case hTIPRO:
  862.         windgoto(0, 0);
  863.         inregs.h.ah = 0x09;
  864.         inregs.h.al = ' ';
  865.         inregs.h.bl = P(P_CO);
  866.         inregs.x.cx = 80 * 25;
  867.         int86(crt_int, &inregs, &outregs);
  868.         if (lines > 25) lines = 25;
  869.         break;
  870.     }
  871.  
  872.     return(lines);
  873. }
  874.  
  875. int
  876. set_43(lines)            /* Set display to 43/50 line mode */
  877. int    lines;
  878. {
  879.     union    REGS    inregs, outregs;
  880.  
  881.     switch (host_type) {
  882.     case hIBMPC:
  883.         inregs.x.ax = 0x1112;
  884.         inregs.h.bl = 0;
  885.         int86(crt_int, &inregs, &outregs);
  886.         inregs.x.ax = 0x1200;
  887.         inregs.h.bl = 0x20;
  888.         int86(crt_int, &inregs, &outregs);
  889.         inregs.h.ah = 0x01;
  890.         inregs.x.cx = 0x0707;
  891.         int86(crt_int, &inregs, &outregs);
  892.         break;
  893.     case hTIPRO:
  894.         if (lines > 25) lines = 25;
  895.         break;
  896.     }
  897.  
  898.     return(lines);
  899. }
  900.  
  901. #else        /* Not BIOS */
  902.  
  903. void set_25 ()
  904. {
  905.     send_setmode (bgn_mode);
  906. }
  907.  
  908. void set_43 ()
  909. {
  910.     send_setmode (43);
  911. }
  912.  
  913. void send_setmode (m)
  914. int m;
  915. {
  916.     outone('\033');
  917.     outone('[');
  918.  
  919.     /* Convert 2-digit decimal to ASCII */
  920.     if (m >= 10)
  921.         outone( m/10 + '0' );
  922.     outone( m%10 + '0' );
  923.     outone ('h');
  924. }
  925.  
  926. #endif        /* Not BIOS */
  927.  
  928. #ifdef BIOS
  929. /*
  930.  *    The rest of the file is BIOS-specific
  931.  */
  932.  
  933. void
  934. bios_t_ci()                /* Make cursor invisible */
  935. {
  936.     union    REGS    inregs, outregs;
  937.  
  938.     if (sav_curattr == 0) {
  939.         inregs.h.ah = 0x03;
  940.         inregs.h.bh = bgn_page;
  941.         int86(crt_int, &inregs, &outregs);
  942.         sav_curattr = outregs.x.cx;
  943.         inregs.h.ah = 0x01;
  944.         inregs.x.cx = 0x2000;
  945.         int86(crt_int, &inregs, &outregs);
  946.     }
  947. }
  948.  
  949. void
  950. bios_t_cv()                /* Make cursor visible */
  951. {
  952.     union    REGS    inregs, outregs;
  953.  
  954.     if (sav_curattr != 0) {
  955.         inregs.h.ah = 0x01;
  956.         inregs.h.bh = bgn_page;
  957.         inregs.x.cx = sav_curattr;
  958.         int86(crt_int, &inregs, &outregs);
  959.         sav_curattr = 0;
  960.     }
  961. }
  962.  
  963. /*
  964.  * O.K., I have tried to keep bios.c as "pure" as possible. I.e., I have used
  965.  * BIOS calls for everything instead of going for all-out speed by using
  966.  * direct-video access for updating the display - after all, I named it this
  967.  * module bios.c.  There is one area, however, where using the BIOS is just
  968.  * too much of a compromise... the TI Pro's "scroll display" functions are so
  969.  * slow and ugly that I hate them.  True, they are very flexible, but their
  970.  * poor on-screen appearance and low performance are a liability - you prob-
  971.  * ably think I'm exaggerating, but you're wrong - it is truly bad.  There-
  972.  * fore, I am bypassing them and scrolling the screen myself; something I
  973.  * nearly always do.  From a purist like me, that really says something.
  974.  */
  975.  
  976. void
  977. bios_t_dl(r,l)                /* Delete lines */
  978. int r, l;
  979. {
  980.     char    far    *end;        /* End ptr for TI Pro screen */
  981.     char    far    *dst;        /* Dest ptr for scrolling TI Pro scrn */
  982.     char    far    *src;        /* Src  ptr for scrolling TI Pro scrn */
  983.  
  984.     union    REGS    inregs, outregs;
  985.  
  986.     switch (host_type) {
  987.     case hIBMPC:
  988.         inregs.h.ah = 0x06;
  989.         inregs.h.al = l;
  990.         inregs.h.bh = P(P_CO);
  991.         inregs.h.ch = r;
  992.         inregs.h.cl = 0;
  993.         inregs.h.dh = Rows - 1;
  994.         inregs.h.dl = Columns - 1;
  995.         int86(crt_int, &inregs, &outregs);
  996.         break;
  997.     case hTIPRO:
  998.         inregs.h.ah = 0x17;
  999.         int86(crt_int, &inregs, &outregs);
  1000.         dst = MK_FP(0xDE00, outregs.x.dx + (r * Columns));
  1001.         src = dst + (l * Columns);
  1002.         end = MK_FP(0xDE00, outregs.x.dx + ((Rows - 1) * Columns));
  1003.         while (src < end) *dst++ = *src++;
  1004.         while (dst < end) *dst++ = ' ';
  1005.         break;
  1006.     }
  1007. }
  1008.  
  1009. void
  1010. bios_t_ed()                /* Home cursor, erase display */
  1011. {
  1012.     union    REGS    inregs, outregs;
  1013.  
  1014.     windgoto(0, 0);
  1015.  
  1016.     inregs.h.ah = 0x09;
  1017.     inregs.h.al = ' ';
  1018.     inregs.h.bh = bgn_page;
  1019.     inregs.h.bl = P(P_CO);
  1020.     inregs.x.cx = Columns * Rows;
  1021.     int86(crt_int, &inregs, &outregs);
  1022. }
  1023.  
  1024. void
  1025. bios_t_el()                /* Erase to end-of-line */
  1026. {
  1027.     short    ccol;
  1028.  
  1029.     union    REGS    inregs, outregs;
  1030.  
  1031.     inregs.h.ah = 0x03;
  1032.     inregs.h.bh = bgn_page;
  1033.     int86(crt_int, &inregs, &outregs);
  1034.  
  1035.     inregs.h.ah = 0x09;
  1036.     inregs.h.al = ' ';
  1037.     inregs.h.bl = P(P_CO);
  1038.  
  1039.     ccol = host_type == hIBMPC ? outregs.h.dl : outregs.h.dh;
  1040.  
  1041.     inregs.x.cx = Columns - ccol;
  1042.     int86(crt_int, &inregs, &outregs);
  1043. }
  1044.  
  1045. /* As in the delete-line function, we scroll the TI display ourselves
  1046.  * rather than the use the slow-and-ugly software scroll in the BIOS.  See
  1047.  * the remarks for bios_t_dl() additional information.
  1048.  */
  1049.  
  1050. void
  1051. bios_t_il(r,l)                /* Insert lines */
  1052. int r, l;
  1053. {
  1054.     char    far    *end;        /* End ptr for TI Pro screen */
  1055.     char    far    *dst;        /* For scrolling TI Pro screen */
  1056.     char    far    *src;        /* For scrolling TI Pro screen */
  1057.  
  1058.     union    REGS    inregs, outregs;
  1059.  
  1060.     switch (host_type) {
  1061.     case hIBMPC:
  1062.         inregs.h.ah = 0x07;
  1063.         inregs.h.al = l;
  1064.         inregs.h.bh = P(P_CO);
  1065.         inregs.h.ch = r;
  1066.         inregs.h.cl = 0;
  1067.         inregs.h.dh = Rows - 1;
  1068.         inregs.h.dl = Columns - 1;
  1069.         int86(crt_int, &inregs, &outregs);
  1070.         break;
  1071.     case hTIPRO:
  1072.         inregs.h.ah = 0x17;
  1073.         int86(crt_int, &inregs, &outregs);
  1074.         dst = MK_FP(0xDE00, outregs.x.dx + (Columns * (Rows - 1)) - 1);
  1075.         src = dst - (Columns * l);
  1076.         end = MK_FP(0xDE00, outregs.x.dx + (Columns * r));
  1077.         while (src >= end) *dst-- = *src--;
  1078.         src = MK_FP(0xDE00, outregs.x.dx + (r * Columns));
  1079.         end = src + (l * Columns);
  1080.         while (src < end) *src++ = ' ';
  1081.         break;
  1082.     }
  1083. }
  1084.  
  1085. void
  1086. bios_t_rc()                /* Restore saved cursor position */
  1087. {
  1088.     union    REGS    inregs, outregs;
  1089.  
  1090.     inregs.h.ah = 0x02;
  1091.     inregs.h.bh = bgn_page;
  1092.     inregs.x.dx = sav_curpos;
  1093.     int86(crt_int, &inregs, &outregs);
  1094. }
  1095.  
  1096. void
  1097. bios_t_sc()                /* Save cursor position */
  1098. {
  1099.     union    REGS    inregs, outregs;
  1100.  
  1101.     inregs.h.ah = 0x03;
  1102.     inregs.h.bh = bgn_page;
  1103.     int86(crt_int, &inregs, &outregs);
  1104.     sav_curpos = outregs.x.dx;
  1105. }
  1106.  
  1107. #endif
  1108.